package com.gary.util;
import cn.hutool.core.util.StrUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.*;

/**
 * 反射工具类型
 *
 * @author Homan Liang
 * @date 2019/11/7
 */
public class ReflectUtil {
    /**
     * 日志
     */
    private static final Logger logger = LoggerFactory.getLogger(ReflectUtil.class);

    /**
     * 设置字段值
     * @param t		对应实体
     * @param field		字段
     * @param fieldName		字段名称
     * @param value			字段值
     */
    public static<T> void setFieldValue(T t, Field field, String fieldName, String value){
        String name = field.getName();
        //判断该字段是否和目标字段相同
        if (!fieldName.equals(name)) {
            return;
        }
        //获取字段的类型
        Type type = field.getType();
        //获取字段的修饰符号码
        int typeCode = field.getModifiers();
        //获取字段类型的名称
        String typeName = type.toString();
        try {
            switch (typeName) {
                case "class java.lang.String":
                    if (Modifier.isPublic(typeCode)) {
                        field.set(t, value);
                    } else {
                        Method method = t.getClass().getMethod("set" + getMethodName(fieldName), String.class);
                        method.invoke(t, value);
                    }
                    break;
                case "double":
                    if(Modifier.isPublic(typeCode)){
                        field.setDouble(t, Double.valueOf(value));
                    }else{
                        Method method = t.getClass().getMethod("set" + getMethodName(fieldName),double.class);
                        method.invoke(t, Double.valueOf(value));
                    }
                    break;
                case "int":
                    if(Modifier.isPublic(typeCode)){
                        field.setInt(t, Integer.valueOf(value));
                    }else{
                        Method method = t.getClass().getMethod("set" + getMethodName(fieldName),int.class);
                        method.invoke(t, Integer.valueOf(value));
                    }
                    break;
                case "float":
                    if(Modifier.isPublic(typeCode)){
                        field.setFloat(t, Float.valueOf(value));
                    }else{
                        Method method = t.getClass().getMethod("set" + getMethodName(fieldName), float.class);
                        method.invoke(t, Float.valueOf(value));
                    }
                    break;
            }
        } catch (Exception e) {
            logger.error(e.toString());
        }
    }

    /**
     * 把字段名称第一个字母换成大写
     * @param fieldName		字段名称
     * @return
     * @throws Exception	异常处理
     */
    private static String getMethodName(String fieldName){
        byte[] items = fieldName.getBytes();
        items[0] = (byte) ((char)items[0] - 'a' + 'A');
        return new String(items);
    }

    /**
     * 根据字段名称获取指定Field字段
     * @param clazz		实体的字节码文件
     * @param filedName		字段的名称
     * @return	返回对应的字符按Field或者返回null
     */
    public static Field getField(Class<?> clazz, String filedName){
        if (clazz == null || StrUtil.isBlank(filedName)) {
            throw new IllegalArgumentException("params is illegal");
        }
        Field[] fields = clazz.getDeclaredFields();
        return getFieldByName(fields, filedName);
    }

    /**
     * 根据字段名称获取指定的Field
     * @param fields	字段集合
     * @param fieldName	 字段名称
     * @return	返回对应的Field字段或者返回null
     */
    public static Field getFieldByName(Field[] fields, String fieldName){
        if (fields == null || fields.length == 0 || StrUtil.isBlank(fieldName)) {
            throw new IllegalArgumentException("params is illegal");
        }
        for (Field field : fields) {
            String name = field.getName();
            //判断该字段是否和目标字段相同
            if (fieldName.equals(name)) {
                return field;
            }
        }
        return null;
    }

    /**
     * 判断该字段是否为FieldName对应字段
     * @param field		Field字段
     * @param fieldName		目标字段
     * @return	是，返回true；否，返回false
     */
    public static boolean isFiledWithName(Field field, String fieldName){
        if(field == null || StrUtil.isBlank(fieldName)){
            throw new IllegalArgumentException("params is illegal");
        }
        if (fieldName.equals(field.getName())) {
            return true;
        }
        return false;
    }

    /**
     * 根据文件路径 获取反射对象并执行对应方法
     * @param methodPath 方法路径
     * @param  方法参数类型
     * @return
     */
    public static <T> T execMethod(String methodPath, Class<?> paramType, Object paramValue){
        try {
            int lastIndex = methodPath.lastIndexOf(".");
            int length = methodPath.length();

            //获取类名
            String className = methodPath.substring(0, lastIndex);
            //获取方法名
            String methodName = methodPath.substring(lastIndex + 1, length);
            // 获取字节码文件对象
            Class c = Class.forName(className);

            Constructor con = c.getConstructor();
            Object obj = con.newInstance();

            // public Method getMethod(String name,Class<?>... parameterTypes)
            // 第一个参数表示的方法名，第二个参数表示的是方法的参数的class类型
            Method method = c.getMethod(methodName, paramType);
            // 调用obj对象的 method 方法
            Object objValue = method.invoke(obj, paramValue);

            return (T)objValue;
        }catch (Exception e){
            logger.error(e.toString());
        }
        return null;
    }
}
